package validator

import (
	"errors"
	"log/slog"
	"os"
	"sync"
	"time"

	"gitee.com/yanwc/license/internal/validator"
	"github.com/mcuadros/go-defaults"
)

var once sync.Once

// Config 验证器配置
type Config struct {
	NTPServers   []string `default:"[ntp.ntsc.ac.cn,cn.ntp.org.cn,edu.ntp.org.cn,time.pool.aliyun.com,time1.cloud.tencent.com]"`
	LicensePath  string   `default:""`
	PublicKeyPEM string   `default:""`
	MaxRetries   int      `default:"5"`
	AllowOffline bool     `default:"false"`
}

// TimeValidator 时间验证器
type TimeValidator struct {
	ntpClient      *validator.NTPClient
	licenseChecker *validator.LicenseValidator
	config         *Config
}

// NewTimeValidator 创建时间验证器
func NewTimeValidator(config *Config) *TimeValidator {
	defaults.SetDefaults(config)
	slog.Info("License: Load time validator config success", "config", config)
	var ntpClient *validator.NTPClient
	if len(config.NTPServers) > 0 {
		ntpClient = validator.NewNTPClient(config.NTPServers[0])
	}

	lv, err := NewLicenseValidator(config.LicensePath, config.PublicKeyPEM)
	if err != nil {
		slog.Error("License: Failed new license validator", "error", err)
		os.Exit(1)
	}
	slog.Info("License: Create license validator success", "license_path", config.LicensePath, "license_public_key_pem", config.PublicKeyPEM)
	return &TimeValidator{
		ntpClient:      ntpClient,
		licenseChecker: lv,
		config:         config,
	}
}

// Validate 执行完整验证
func (tv *TimeValidator) Validate() (*validator.LicenseInfo, error) {
	// 1. 验证许可证
	licenseInfo, err := tv.licenseChecker.ValidateLicense()
	if err != nil {
		slog.Error("License: Failed to validate license", "error", err)
		return nil, err
	}
	// 2. 网络时间验证
	ntpTime, err := tv.ntpClient.GetTimeWithRetry(tv.config.MaxRetries)
	if err != nil {
		if tv.config.AllowOffline {
			// 离线模式：使用系统时间，但进行基本检查
			if !tv.isSystemTimeReasonable() {
				slog.Error("License: System time appears to be tampered with")
				return nil, errors.New("system time appears to be tampered with")
			}
			return licenseInfo, nil
		}
		return nil, err
	}

	// 3. 检查时间有效性
	if !tv.licenseChecker.IsTimeValid(ntpTime) {
		slog.Error("License: Failed to check ntp time valid")
		return nil, errors.New("time validation failed: possible time tampering detected")
	}

	return licenseInfo, nil
}

// isSystemTimeReasonable 检查系统时间是否合理
func (tv *TimeValidator) isSystemTimeReasonable() bool {
	currentTime := time.Now()

	// 检查时间是否在许可证有效期内
	licenseInfo, err := tv.licenseChecker.ValidateLicense()
	if err != nil {
		return false
	}

	// 系统时间不应早于构建时间（简单检查）
	buildTime, _ := time.Parse("2006-01-02", "2024-01-01")
	if currentTime.Before(buildTime) {
		return false
	}

	// 系统时间应在许可证有效期合理范围内
	if currentTime.After(licenseInfo.ExpiryDate.Add(24 * time.Hour)) {
		return false
	}

	return true
}

// SimpleValidate 简化验证（仅检查许可证）
func (tv *TimeValidator) SimpleValidate() error {
	_, err := tv.licenseChecker.ValidateLicense()
	return err
}

// Setup 安装证书许可
func (tv *TimeValidator) Setup(d time.Duration, slient bool) error {
	once.Do(func() {
		go func() {
			ticker := time.NewTicker(d)
			for range ticker.C {
				if _, err := tv.Validate(); err != nil {
					slog.Error("License: Failed to valid license,system exit!!", "error", err)
					os.Exit(1)
				}
				if !slient {
					slog.Info("The license is valid")
				}

			}
		}()
	})

	return nil
}
